package org.energy;
/**
 * Copyright (c) 2008, 2012 Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 */

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Random;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.util.Duration;

/**
 * An advanced line chart with a variety of actions and settable properties.
 *
 * @see javafx.scene.chart.LineChart
 * @see javafx.scene.chart.Chart
 * @see javafx.scene.chart.NumberAxis
 * @see javafx.scene.chart.XYChart
 */
public class AdvancedLineChartSample extends Application {

    private Label label = new Label("Current position: ");
    private Label positionLabel = new Label("23,45");
    private Label targetInfoLabel = new Label(" --- ");
    private int MAX_X = 800 + 76;
    private int MAX_Y = 600 + 120;
    private Timeline animation;
    private ArrayList<FlightPoint> flight = new ArrayList<FlightPoint>();

    XYChart.Series<Number, Number> seriesCopy = new XYChart.Series<Number, Number>();
    XYChart.Series<Number, Number> animationSeries = new XYChart.Series<Number, Number>();
    LineChart<Number, Number> lc;
    private int time;
    private int currentFlightPoint;
    protected Socket fromserver;
    protected BufferedReader in;
    protected PrintWriter out;

    private void init(Stage primaryStage) {
        Group root = new Group();
        primaryStage.setScene(new Scene(root));
        root.getChildren().add(createChart());
        Button buttonClear = new Button("��������");
        buttonClear.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                //log mouse move to console, method listed below
                System.out.println("Mouse clicked, x: " + me.getX() + ", y: " + me.getY());

//                System.out.println(seriesCopy.getData());
//                seriesCopy.getData().add(new XYChart.Data<Number,Number>(me.getX(), me.getY()));
                int size = lc.getData().size();
//                for (int i=0;i<size;i++){
//                	lc.getData().remove(i);
//                }

                seriesCopy.getData().clear();
                lc.getData().clear();
                System.out.println("clearing data");
                //flight.clear();
                lc.getData().add(seriesCopy);

            }
        });

        Button buttonNew = new Button("�������� �����");
        buttonNew.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                //log mouse move to console, method listed below
                System.out.println("Mouse clicked, x: " + me.getX() + ", y: " + me.getY());

//                System.out.println(seriesCopy.getData());
//                seriesCopy.getData().add(new XYChart.Data<Number,Number>(me.getX(), me.getY()));
                seriesCopy.getData().clear();
                flight.clear();
                for (int i = 0; i < flight.size(); i++) {
                    //seriesCopy.getData().add(new XYChart.Data<Number,Number>(flight.get(flight.size()-1).x,flight.get(flight.size()-1).y));
                }
                lc.getData().add(seriesCopy);
            }
        });

        Button buttonStatic = new Button("�������� �����������");
        buttonStatic.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                AddStaticData(lc);
            }
        });

        Button buttonStohastic = new Button("�������� ���������");
        buttonStohastic.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                addRandomStaticData(lc);
            }
        });

        animation = new Timeline();
        time = 0;

        animation.getKeyFrames().add(new KeyFrame(Duration.millis(1000), new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent actionEvent) {
                double x = 0;
                double y = 0;
                System.out.println("x,y = " + getCurrentCoordingates());
                if (time < flight.get(flight.size() - 1).time) {
                    if (time < flight.get(currentFlightPoint).time) {
                        //calculate coordinates
                    } else {
                        currentFlightPoint++;
                    }

                    //calculate coordinates
                    x = calculateCurrentX();
                    y = calculateCurrentY();

                    out.println(" x: " + x + " y: " + y);

                    seriesCopy.getData().add(new XYChart.Data<Number, Number>((int) x, (int) y));
                    System.out.println("t = " + time + " : " + flight.get(currentFlightPoint).time);
                    targetInfoLabel.setText(" ���� x: " + x + " y: " + y + " v: "
                            + flight.get(currentFlightPoint).time + " t: " + time);
                } else {
                    animation.stop();
                    currentFlightPoint = 0;
                    time = 0;
                }
                System.out.println("some event happend: " + time++ + flight.size());

            }

        }));


        animation.setCycleCount(Animation.INDEFINITE);
        Button buttonStartAnimation = new Button("Start");
        buttonStartAnimation.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {

                connectToServer();

                animation.play();
                calculateDistance();
                setSpeed();
                setTime();
            }


        });

        Button buttonStopAnimation = new Button("Stop");
        buttonStopAnimation.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                animation.stop();
                time = 0;
            }
        });


        Button buttonOpen = new Button("�������");
        buttonOpen.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                System.out.println("Open button pressed");
                FileChooser fileChooser = new FileChooser();

                //Set extension filter
                //FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("AVI files (*.avi)", "*.avi");
                //fileChooser.getExtensionFilters().add(extFilter);

                //Show open file dialog
                File file = fileChooser.showOpenDialog(null);
                flight.clear();
                readFileToObject(flight, file.getPath());
                seriesCopy.getData().clear();
                lc.getData().clear();
                System.out.println("file choosed: " + file.getPath() + " flight : " + flight.size());
                //adding points to line chart
                for (int i = 0; i < flight.size(); i++) {
                    seriesCopy.getData().add(new XYChart.Data<Number, Number>(flight.get(i).x, flight.get(i).y));
                }
                lc.getData().add(seriesCopy);

            }
        });

        Button buttonSave = new Button("���������");
        buttonSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                System.out.println("Save button pressed");
                FileChooser fileChooser = new FileChooser();

                //Set extension filter
                //FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("AVI files (*.avi)", "*.avi");
                //fileChooser.getExtensionFilters().add(extFilter);

                //Show open file dialog
                File file = fileChooser.showSaveDialog(null);

                objectToFile(flight, file.getPath());

                System.out.println("file choosed: " + file.getPath() + " flight : " + flight.size());
            }
        });


        VBox vBox = new VBox();
        HBox hBox2 = new HBox();
        HBox hBox = new HBox();


        hBox.getChildren().add(buttonNew);
        hBox.getChildren().add(buttonClear);
        //hBox.getChildren().add(buttonStatic);
        //hBox.getChildren().add(buttonStohastic);
        hBox.getChildren().add(buttonStartAnimation);
        hBox.getChildren().add(buttonStopAnimation);
        hBox.getChildren().add(buttonOpen);
        hBox.getChildren().add(buttonSave);


        hBox2.getChildren().add(label);
        hBox2.getChildren().add(positionLabel);
        hBox2.getChildren().add(targetInfoLabel);
        vBox.getChildren().add(hBox2);
        vBox.getChildren().add(hBox);
        root.getChildren().add(vBox);

    }

    private void connectToServer() {
        System.out.println("Connecting to... " + "localhost");

        try {
            fromserver = new Socket("localhost", 4444);

            in = new BufferedReader(new
                    InputStreamReader(fromserver.getInputStream()));
            out = new
                    PrintWriter(fromserver.getOutputStream(), true);

        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    protected String getCurrentCoordingates() {
        // TODO Auto-generated method stub
        return null;
    }

    private double calculateCurrentY() {
        return (flight.get(currentFlightPoint).y - flight.get(currentFlightPoint - 1).y) *
                (time - flight.get(currentFlightPoint - 1).time)
                / (flight.get(currentFlightPoint).time - flight.get(currentFlightPoint - 1).time)
                + flight.get(currentFlightPoint - 1).y;
    }

    private double calculateCurrentX() {
        return (flight.get(currentFlightPoint).x - flight.get(currentFlightPoint - 1).x) *
                (time - flight.get(currentFlightPoint - 1).time)
                / (flight.get(currentFlightPoint).time - flight.get(currentFlightPoint - 1).time)
                + flight.get(currentFlightPoint - 1).x;
    }


    private double calculateDistance() {
        for (int i = 1; i < flight.size(); i++) {
            flight.get(i).distance = Math.sqrt((flight.get(i).x - flight.get(i - 1).x) *
                    (flight.get(i).x - flight.get(i - 1).x)
                    + (flight.get(i).y - flight.get(i - 1).y) *
                    (flight.get(i).y - flight.get(i - 1).y));
            System.out.println("flight distance " + i + " = " + flight.get(i).distance);
        }
        return 0;
    }

    private double setSpeed() {
        Random random = new Random(7);
        for (int i = 0; i < flight.size(); i++) {
            flight.get(i).v = random.nextInt(10) + 10;
            System.out.println("flight speed  " + i + " = " + flight.get(i).v);
        }
        return 0;
    }

    private double setTime() {
        for (int i = 1; i < flight.size(); i++) {
            flight.get(i).time = flight.get(i - 1).time + (flight.get(i).distance / flight.get(i).v);
            System.out.println("flight time  " + i + " = " + flight.get(i).time);
        }
        return 0;
    }

    protected LineChart<Number, Number> createChart() {
        final NumberAxis xAxis = new NumberAxis(0, 400, 50);
        final NumberAxis yAxis = new NumberAxis(0, 400, 50);
        lc = new LineChart<Number, Number>(xAxis, yAxis);

        // setup chart
        lc.setTitle("                                       ����� �������");
        lc.setMinSize(MAX_X, MAX_Y);
        xAxis.setLabel("������");
        yAxis.setLabel("���������");
        xAxis.setAnimated(true);

        // add starting data

//        AddStaticData(lc);


        seriesCopy.setName("������������ �����");
        seriesCopy.getData().add(new XYChart.Data<Number, Number>(0d, 0d));
//        seriesCopy.getData().add(new XYChart.Data<Number,Number>(40d + 10, 80d + 10));

//        addRandomStaticData(lc);

        // we can set mouse event to any node, also on the rectangle
        lc.setOnMouseMoved(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                //log mouse move to console, method listed below
                //System.out.println("Mouse moved, x: " + me.getX() + ", y: " + me.getY() );
                //System.out.println(seriesCopy.getData());
                positionLabel.setText("x: " + me.getX() + ", y: " + me.getY());
            }
        });

        // we can set mouse event to any node, also on the rectangle
        lc.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent me) {
                //log mouse move to console, method listed below
                System.out.println("Mouse clicked, x: " + me.getX() + ", y: " + me.getY());
                System.out.println(seriesCopy.getData());
                flight.add(new FlightPoint(calculateX(me.getX()), calculateY(me.getY()), 1000));
                seriesCopy.getData().add(new XYChart.Data<Number, Number>(flight.get(flight.size() - 1).x, flight.get(flight.size() - 1).y));
//                lc.getData().remove(seriesCopy);
//                lc.getData().add(seriesCopy);
            }
        });

        //lc.getData().add(seriesCopy);
        return lc;


    }

    private double calculateX(double d) {
        return (d - 60) / 2;
    }

    private double calculateY(double d) {
        return (MAX_Y - d - 80) / 1.5;
    }

    private void addRandomStaticData(final LineChart<Number, Number> lc) {
        for (int i = 0; i < 1; i++) {
            XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
            series.setName("����� � " + lc.getData().size());
            double x = 0;
            while (x < 95) {
                series.getData().add(new XYChart.Data<Number, Number>(x, Math.random() * 99));
                x += 5 + (15 * Math.random());
            }
            series.getData().add(new XYChart.Data<Number, Number>(99d, Math.random() * 99));
            lc.getData().add(series);
        }
    }

    private void AddStaticData(final LineChart<Number, Number> lc) {
        for (int i = 0; i < 1; i++) {
            XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
            series.setName("����� � " + lc.getData().size());
            series.getData().add(new XYChart.Data<Number, Number>(0d, 0d));
            series.getData().add(new XYChart.Data<Number, Number>(40d + 10 * i, 80d + 10 * i));
            series.getData().add(new XYChart.Data<Number, Number>(50d + 10 * i, 90d + 10 * i));
            series.getData().add(new XYChart.Data<Number, Number>(70d + 10 * i, 130d + 10 * i));
            series.getData().add(new XYChart.Data<Number, Number>(170d + 10 * i, 122d + 10 * i));
            series.getData().add(new XYChart.Data<Number, Number>(0d, 0d));
            lc.getData().add(series);
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        init(primaryStage);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    public boolean objectToFile(Object object, String fileName) {
        try {
            File file = new File(fileName);
//			int n = 0;
//			do {
//				file = new File(fileName + "." + n);
//				n++;
//			} while (file.exists());

            FileOutputStream fileOut = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fileOut);
            oos.writeObject(object);
            oos.close();
        } catch (FileNotFoundException e) {
            return false;
        } catch (IOException e) {
            return false;
        }
        return true;
    }

    public Object readFileToObject(Object object, String fileName) {
        File f = new File(fileName);
        System.out.println("reading file " + fileName);
        FileInputStream fis = null;
        ObjectInputStream in = null;
        try {
            fis = new FileInputStream(f);
            in = new ObjectInputStream(fis);
            object = in.readObject();
            flight = (ArrayList<FlightPoint>) object;
            ArrayList<FlightPoint> points = (ArrayList<FlightPoint>) object;
            System.out.println("object size = " + object.toString() + "-" + points.size());
            in.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        return object;
    }
}

